// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: donggu, jhkim

#include "coin2/base/config/app_config.h"
#include "coin2/base/config/args.h"
#include "coin2/base/log.h"
#include "coin2/strategy/linear_model/strategy.h"

using namespace coin2::exchange::base::symbology;
using namespace coin2::base::config;
using namespace coin2::exchange::feed;
using namespace coin2::app;
using ::coin2::strategy::linear_model::LmStrategy;

namespace coin2::base::config {

void AddSimulationOptions(cxxopts::Options* opt) {
  opt->add_options()("sim_result_filepath", "", cxxopts::value<std::string>());
}

}  // namespace coin2::base::config

int main(int argc, char* argv[]) {
  InitModules();

  DriverConfig app;

  cxxopts::Options opt("lm-agg pilot", "lm-agg Live Pilot");
  opt.add_options()("lm_strat_json", "model config path", cxxopts::value<std::string>());
  opt.add_options()("kline_json", "kline path for feature",
      cxxopts::value<std::string>()->default_value(""));
  opt.add_options()("dryrun", "if dryrun, enable OE && disable OG", cxxopts::value<bool>());
  opt.add_options()("hours_warmedup", "hours_warmup that is already reflected",
      cxxopts::value<double>()->default_value("0.0"));
  AddDriverOptions(&opt);
  AddIntervalOptions(&opt);
  AddProductOptions(&opt);
  AddSimulationOptions(&opt);
  AddFeedArchiveOptions(&opt);

  auto res = opt.parse(argc, argv);
  ParseDriverOptions(res, &app);
  ParseIntervalOptions(
      res,
      app.mutable_feed()->mutable_common()->mutable_archive()->mutable_interval());
  ParseProductOptions(res, app.mutable_feed());

  for (auto& exchange : *(app.mutable_order()->mutable_exchanges())) {
    if (exchange.second.has_key_filepath()) {
      exchange.second.set_key_filepath(std::string());
    }
  }

  #ifndef VERBOSE_SIM
  app.mutable_log()->set_log_file("");
  #endif

  ::coin2::base::InitLogging(argv[0], app.log());

  auto begin_end = GetEnclosingInterval(app);
  CHECK_GT(begin_end.first, 0);

  int64_t nanosecs_warmedup = static_cast<int64_t>(res["hours_warmedup"].as<double>() * 3600 * 1e9);

  auto* mut_sim_config2 = app.mutable_order()->mutable_common()->mutable_sim_config2();
  for (int i = 0; i < mut_sim_config2->accounts_size(); ++i) {
    mut_sim_config2->mutable_accounts(i)->set_start_timestamp(begin_end.first);
    mut_sim_config2->mutable_accounts(i)->set_warmup_timestamp(begin_end.first + nanosecs_warmedup);
    if (res.count("sim_result_filepath") > 0) {
      std::string sim_result_filepath = res["sim_result_filepath"].as<std::string>();
      boost::replace_all(
          sim_result_filepath,
          ".pb.",
          ToDateStr(begin_end.first) + "/" +
          mut_sim_config2->mutable_accounts(i)->relative_norm() + "." +
          std::to_string(mut_sim_config2->mutable_accounts(i)->sim_account_id()) +
          ".pb.");
      mut_sim_config2->mutable_accounts(i)->set_sim_result_filepath(sim_result_filepath);
    }
  }
  LOG(INFO) << fmt::format("kline: {}",
      res["kline_json"].as<std::string>());
  LmStrategy lm_strategy(
      res["lm_strat_json"].as<std::string>(),
      res["kline_json"].as<std::string>(),
      begin_end.first,
      nanosecs_warmedup,
      true);  // simulation
  Driver driver(app, &lm_strategy);
  driver.Run();
  lm_strategy.onCleanup(&driver);

  LOG(INFO) << "# submits: " << lm_strategy.GetSubmitCnt();
  // == 0 then return 1 else 0
  return lm_strategy.GetSubmitCnt() == 0;
}
